home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / ds5000.md / vm3max.c < prev    next >
C/C++ Source or Header  |  1991-08-09  |  63KB  |  2,437 lines

  1. /* vmPmax.c -
  2.  *
  3.  *         This file contains all hardware dependent routines for the 3MAX.
  4.  *
  5.  * Copyright (C) 1989 Digital Equipment Corporation.
  6.  * Permission to use, copy, modify, and distribute this software and
  7.  * its documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appears in all copies.  
  9.  * Digital Equipment Corporation makes no representations about the
  10.  * suitability of this software for any purpose.  It is provided "as is"
  11.  * without express or implied warranty.
  12.  */
  13.  
  14. #ifndef lint
  15. static char rcsid[] = "$Header: /sprite/src/kernel/vm/ds5000.md/RCS/vm3max.c,v 1.10 91/08/09 15:02:55 shirriff Exp $ SPRITE (DECWRL)";
  16. #endif not lint
  17.  
  18. #include <sprite.h>
  19. #include <vm3maxConst.h>
  20. #include <vm.h>
  21. #include <vmInt.h>
  22. #include <vmMach.h>
  23. #include <vmMachInt.h>
  24. #include <list.h>
  25. #include <mach.h>
  26. #include <proc.h>
  27. #include <sched.h>
  28. #include <stdlib.h>
  29. #include <sync.h>
  30. #include <sys.h>
  31. #include <dbg.h>
  32. #include <bstring.h>
  33. #include <machMon.h>
  34.  
  35. #if (MACH_MAX_NUM_PROCESSORS == 1) /* uniprocessor implementation */
  36. #undef MASTER_LOCK
  37. #undef MASTER_UNLOCK
  38. #define MASTER_LOCK(x) DISABLE_INTR()
  39. #define MASTER_UNLOCK(x) ENABLE_INTR()
  40. #else
  41.  
  42. /*
  43.  * The master lock to synchronize access to the tlb.
  44.  */
  45. static Sync_Semaphore vmMachMutex;
  46. static Sync_Semaphore *vmMachMutexPtr = &vmMachMutex;
  47.  
  48. #endif
  49.  
  50. /*
  51.  * The environment variables on the memory bitmap:
  52.  */
  53. extern char mach_BitmapLen[];
  54. extern char mach_BitmapAddr[];
  55.  
  56. /*----------------------------------------------------------------------
  57.  * 
  58.  *             Hardware data structures
  59.  *
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. /*
  65.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  66.  * We are only allowed to use the second byte of the flags.
  67.  *
  68.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  69.  *                    the mapping segment.
  70.  */
  71. #define    USING_MAPPED_SEG    0x100
  72.  
  73. /*
  74.  * The maximum amount of kernel heap available.  Sprite expects the
  75.  * sum of this value and the kernel start to be the kernel end.
  76.  * Since the MIPS machines have a big hole in the address space
  77.  * we have to add 1 Gig to cover the whole.
  78.  *
  79.  * Right now the amount is set to 1 Gig + 128 Meg
  80.  */
  81. int    vmMachKernMemSize = 0x40000000 + 0x8000000;
  82.  
  83. /*
  84.  * Table of info about each physical page on the machine.
  85.  */
  86. typedef struct PhysPage {
  87.     unsigned int    user:        1,
  88.             referenced: 1,
  89.             modified:   1;
  90. } PhysPage;
  91. PhysPage    *vmMachPhysPageArr;
  92.  
  93. /*
  94.  * Kernel mappings for all possible kernel memory.  Each entry contains
  95.  * the LOW tlb entry.
  96.  */
  97. unsigned int    *vmMach_KernelTLBMap;
  98.  
  99. /*
  100.  * PID allocation data structures.  We need a list of free and active
  101.  * PIDs as well as a mapping from segment to pid and back.
  102.  */
  103. typedef struct PIDListElem {
  104.     List_Links        links;
  105.     Proc_ControlBlock    *procPtr;
  106.     int            pid;
  107.     List_Links        tlbList;
  108. } PIDListElem;
  109. static PIDListElem    pidListElems[VMMACH_NUM_PIDS];
  110.  
  111. /*
  112.  * List of free pids.
  113.  */
  114. static List_Links    freePIDListHdr;
  115. static List_Links    *freePIDList = &freePIDListHdr;
  116.  
  117. /*
  118.  * List of active pids.
  119.  */
  120. static List_Links    activePIDListHdr;
  121. static List_Links    *activePIDList = &activePIDListHdr;
  122.  
  123. /*
  124.  * Amount of physical memory.
  125.  */
  126. int    vm_NumPhysPages;
  127.  
  128. extern    Address    vmMemEnd;
  129.  
  130. /*
  131.  * A TLB hash bucket.
  132.  */
  133. typedef struct TLBHashBucket {
  134.     List_Links        links;        /* Links so can be in PID chain. */
  135.     unsigned        low;        /* The TLB low register value. */
  136.     unsigned        high;        /* The TLB high register value. */
  137. } TLBHashBucket;
  138.  
  139. /*
  140.  * The TLB hash table.
  141.  */
  142. TLBHashBucket    vmMachTLBHashTable[VMMACH_NUM_TLB_HASH_ENTRIES];
  143.  
  144. /*
  145.  * Performance counters.  The number of fields cannot
  146.  */
  147. typedef struct {
  148.     int    savedAT;
  149.     int utlbFaultCount;
  150.     int utlbHitCount;
  151.     int modFaultCount;
  152.     int modHitCount;
  153.     int slowModCount;
  154.     int numInserts;
  155.     int numCollisions;
  156.     int numProbes;
  157.     int numFound;
  158. } TLBCounters;
  159. TLBCounters *tlbCountersPtr = (TLBCounters *)(0x80000000 + VMMACH_STAT_BASE_OFFSET);
  160.  
  161. /*
  162.  * Table of TLB entries for the user has kernel pages mapped into
  163.  * their address space.  There is only one such process (the X server).
  164.  */
  165. static unsigned    userMappingTable[VMMACH_USER_MAPPING_PAGES];
  166. static int            userMapIndex;
  167. static Boolean            userMapped = FALSE;
  168. static Proc_ControlBlock    *mappedProcPtr = (Proc_ControlBlock *)NIL;
  169.  
  170. /*
  171.  * Forward declarations.
  172.  */
  173. static int GetNumPages _ARGS_((void));
  174. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  175.     unsigned int virtPage, Boolean segDeletion));
  176. INTERNAL static void TLBHashInsert _ARGS_((int pid, unsigned page,
  177.     unsigned lowReg, unsigned hiReg));
  178. INTERNAL static void TLBHashDelete _ARGS_((int pid, unsigned page));
  179. INTERNAL static void TLBHashFlushPID _ARGS_((int pid));
  180. INTERNAL static TLBHashBucket *TLBHashFind _ARGS_((int pid, unsigned page));
  181. static ReturnStatus VmMach_Alloc _ARGS_((VmMach_SharedData *sharedData,
  182.     int regionSize, Address *addr));
  183. static void VmMach_Unalloc _ARGS_((VmMach_SharedData *sharedData,
  184.     Address addr));
  185.  
  186.  
  187. /*
  188.  * ----------------------------------------------------------------------------
  189.  *
  190.  * VmMach_BootInit --
  191.  *
  192.  *      Do hardware dependent boot time initialization.
  193.  *
  194.  * Results:
  195.  *      None.
  196.  *
  197.  * Side effects:
  198.  *      Hardware page map for the kernel is initialized.  Also the various size
  199.  *     fields are filled in.
  200.  *
  201.  * ----------------------------------------------------------------------------
  202.  */
  203. void
  204. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  205.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  206.     int    *pageSizePtr;
  207.     int    *pageShiftPtr;
  208.     int    *pageTableIncPtr;
  209.     int    *kernMemSizePtr;
  210.     int    *numKernPagesPtr;
  211.     int    *maxSegsPtr;
  212.     int *maxProcessesPtr;
  213. {
  214.     int            numPages;
  215.  
  216. #if (MACH_MAX_NUM_PROCESSORS > 1) /* uniprocessor implementation */
  217.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  218. #endif
  219.  
  220.     /*
  221.      * Do boot time allocation.
  222.      */
  223.     vm_NumPhysPages = GetNumPages();
  224.     vmMachPhysPageArr = 
  225.         (PhysPage *)Vm_BootAlloc(sizeof(PhysPage) * vm_NumPhysPages);
  226.     bzero((char *)vmMachPhysPageArr, sizeof(PhysPage) * vm_NumPhysPages);
  227.  
  228.     numPages = (unsigned) (mach_KernEnd - VMMACH_VIRT_CACHED_START) >> 
  229.                         VMMACH_PAGE_SHIFT;
  230.     vmMach_KernelTLBMap = (unsigned *)Vm_BootAlloc(sizeof(unsigned) * numPages);
  231.     bzero((char *)vmMach_KernelTLBMap, sizeof(unsigned) * numPages);
  232.  
  233.     /*
  234.      * Return lots of sizes to the machine independent module who called us.
  235.      */
  236.     *pageSizePtr = VMMACH_PAGE_SIZE;
  237.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  238.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  239.     *kernMemSizePtr = vmMachKernMemSize;
  240.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  241.     *numKernPagesPtr = vm_NumPhysPages;
  242.     *maxSegsPtr = -1;
  243. }
  244.  
  245.  
  246. /*
  247.  * ----------------------------------------------------------------------------
  248.  *
  249.  * GetNumPages --
  250.  *
  251.  *     Determine how many pages of physical memory there are.
  252.  *
  253.  * Results:
  254.  *     The number of physical pages.
  255.  *
  256.  * Side effects:
  257.  *     None.
  258.  *
  259.  * ----------------------------------------------------------------------------
  260.  */
  261. static int
  262. GetNumPages()
  263. {
  264.     int            i;
  265.     int            pages;
  266.     int            bitmapLen;
  267.     int            *bitmapAddr;
  268.     int            count = 0;
  269.  
  270.  
  271.     count = sscanf(mach_BitmapLen+2,"%x",&bitmapLen);
  272.     if (count != 1) {
  273.     panic("GetNumPages: unable to scan bitmap length.\n");
  274.     }
  275.     count = sscanf(mach_BitmapAddr+2,"%x",&bitmapAddr);
  276.     if (count != 1) {
  277.     panic("GetNumPages: unable to scan bitmap address.\n");
  278.     }
  279.     for (i=0;i<bitmapLen;i++) {
  280.     if (bitmapAddr[i] != 0xffffffff) break;
  281.     }
  282.     pages = i * 32;
  283.     for (;i<bitmapLen;i++) {
  284.     if (bitmapAddr[i] != 0x00000000) {
  285.         printf("Warning: Memory fragmentation at page 0x%x\n",i * 32);
  286.         break;
  287.     }
  288.     }
  289.     Mach_MonPrintf("%d pages of memory\n", pages);
  290.     return(pages); 
  291. }
  292.  
  293.  
  294. /*
  295.  * ----------------------------------------------------------------------------
  296.  *
  297.  * VmMach_AllocKernSpace --
  298.  *
  299.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  300.  *
  301.  * Results:
  302.  *     None.
  303.  *
  304.  * Side effects:
  305.  *     None.
  306.  *
  307.  * ----------------------------------------------------------------------------
  308.  */
  309. Address
  310. VmMach_AllocKernSpace(baseAddr)
  311.     Address    baseAddr;
  312. {
  313.     return(baseAddr);
  314. }
  315.  
  316.  
  317. /*
  318.  * ----------------------------------------------------------------------------
  319.  *
  320.  * VmMach_Init --
  321.  *
  322.  *     Initialize all virtual memory data structures.
  323.  *
  324.  * Results:
  325.  *     None.
  326.  *
  327.  * Side effects:
  328.  *     All virtual memory linked lists and arrays are initialized.
  329.  *
  330.  * ----------------------------------------------------------------------------
  331.  */
  332. /*ARGSUSED*/
  333. void
  334. VmMach_Init(firstFreePage)
  335.     int    firstFreePage;    /* Virtual page that is the first free for the 
  336.              * kernel. */
  337. {
  338.     register    int         i;
  339.  
  340.     /*
  341.      * Initialize pid lists.  0 is invalid and PID 1 is for kernel processes.
  342.      */
  343.     List_Init(freePIDList);
  344.     List_Init(activePIDList);
  345.     for (i = 2; i < VMMACH_NUM_PIDS; i++) {
  346.     List_Insert((List_Links *)&pidListElems[i], 
  347.             LIST_ATREAR(freePIDList));
  348.     pidListElems[i].pid = i;
  349.     List_Init(&pidListElems[i].tlbList);
  350.     }
  351.  
  352.     /*
  353.      * Push vmMemEnd up to the beginning of dynamic memory.
  354.      */
  355.     vmMemEnd = (Address)VMMACH_VIRT_CACHED_START;
  356.     vm_SysSegPtr->numPages = VMMACH_VIRT_CACHED_START_PAGE - 
  357.                 vm_SysSegPtr->offset;
  358.  
  359.     /*
  360.      * Mark all entries in the TLB as invalid.  
  361.      */
  362.     VmMachFlushTLB();
  363.     for (i = 0; i < VMMACH_FIRST_RAND_ENTRY; i++) {
  364.     VmMachWriteIndexedTLB(i, 0, (unsigned)VMMACH_PHYS_CACHED_START_PAGE);
  365.     }
  366.     /*
  367.      * Zero out the TLB fault counters which are in low memory.
  368.      */
  369.     bzero((char *)tlbCountersPtr, sizeof(TLBCounters));
  370. }
  371.  
  372.  
  373. /*
  374.  * ----------------------------------------------------------------------------
  375.  *
  376.  * VmMach_SegInit --
  377.  *
  378.  *      Initialize hardware dependent data for a segment.
  379.  *
  380.  * Results:
  381.  *      None.
  382.  *
  383.  * Side effects:
  384.  *      Minimum and maximum address set in the segment table entry.
  385.  *
  386.  * ----------------------------------------------------------------------------
  387.  */
  388. void
  389. VmMach_SegInit(segPtr)
  390.     Vm_Segment    *segPtr;
  391. {
  392.     /*
  393.      * Set the minimum and maximum virtual addresses for this segment to
  394.      * be as small and as big as possible respectively because things will
  395.      * be prevented from growing automatically as soon as segments run into
  396.      * each other.
  397.      */
  398.     segPtr->minAddr = (Address)0;
  399.     segPtr->maxAddr = (Address)0x7fffffff;
  400. }
  401.  
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * VmMach_SegExpand --
  407.  *
  408.  *    Don't have to do anything.
  409.  *
  410.  * Results:
  411.  *    None.
  412.  *
  413.  * Side effects:
  414.  *    None.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418. /*ARGSUSED*/
  419. void
  420. VmMach_SegExpand(segPtr, firstPage, lastPage)
  421.     Vm_Segment    *segPtr;    /* Segment to expand. */
  422.     int        firstPage;    /* First page to add. */
  423.     int        lastPage;    /* Last page to add. */
  424. {
  425. }
  426.  
  427.  
  428. /*
  429.  * ----------------------------------------------------------------------------
  430.  *
  431.  * VmMach_SegDelete --
  432.  *
  433.  *      Don't have to do anything.
  434.  *
  435.  * Results:
  436.  *      None.
  437.  *
  438.  * Side effects:
  439.  *      None.
  440.  *
  441.  * ----------------------------------------------------------------------------
  442.  */
  443. /*ARGSUSED*/
  444. void
  445. VmMach_SegDelete(segPtr)
  446.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  447. {
  448. }
  449.  
  450.  
  451. /*
  452.  *----------------------------------------------------------------------
  453.  *
  454.  * VmMach_ProcInit --
  455.  *
  456.  *    Initalize the machine dependent part of the VM proc info.
  457.  *
  458.  * Results:
  459.  *    None.
  460.  *
  461.  * Side effects:
  462.  *    Machine dependent proc info is initialized.
  463.  *
  464.  *----------------------------------------------------------------------
  465.  */
  466. void
  467. VmMach_ProcInit(vmPtr)
  468.     register    Vm_ProcInfo    *vmPtr;
  469. {
  470.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  471.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  472.     }
  473.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  474.     vmPtr->machPtr->pid = VMMACH_INV_PID;
  475.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  476.     List_Init(&vmPtr->machPtr->kernSharedList);
  477. }
  478.  
  479.  
  480. /*
  481.  * ----------------------------------------------------------------------------
  482.  *
  483.  * VmMach_SetupContext --
  484.  *
  485.  *      Allocate a PID to the current process.
  486.  *    
  487.  * Results:
  488.  *      PID allocated.
  489.  *
  490.  * Side effects:
  491.  *      PID may be moved to end of active list and an entry may be taken off
  492.  *    of the free list.
  493.  *
  494.  * ----------------------------------------------------------------------------
  495.  */
  496. ENTRY ClientData
  497. VmMach_SetupContext(procPtr)
  498.     register    Proc_ControlBlock    *procPtr;
  499. {
  500.     VmMach_ProcData    *machPtr;
  501.     PIDListElem        *pidPtr;
  502.  
  503.     MASTER_LOCK(vmMachMutexPtr);
  504.  
  505.     machPtr = procPtr->vmPtr->machPtr;
  506.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  507.     /*
  508.      * This is a kernel process or a process that is exiting.  These
  509.      * processes use the kernel's pid.
  510.      */
  511.     machPtr->pid = VMMACH_KERN_PID;
  512.     VmMachSetPID(VMMACH_KERN_PID);
  513.     MASTER_UNLOCK(vmMachMutexPtr);
  514.     return((ClientData)machPtr->pid);
  515.     } 
  516.  
  517.     if (machPtr->pid == VMMACH_INV_PID) {
  518.     /*
  519.      * Allocate us a new PID.
  520.      */
  521.     if (List_IsEmpty(freePIDList)) {
  522.         vmStat.machDepStat.stealPID++;
  523.         pidPtr = (PIDListElem *)List_First(activePIDList);
  524.         pidPtr->procPtr->vmPtr->machPtr->pid = VMMACH_INV_PID;
  525.         VmMachFlushPIDFromTLB(pidPtr->pid);
  526.         TLBHashFlushPID(pidPtr->pid);
  527.     } else {
  528.         pidPtr = (PIDListElem *)List_First(freePIDList);
  529.     }
  530.     machPtr->pid = pidPtr->pid;
  531.     pidPtr->procPtr = procPtr;
  532.     } else {
  533.     pidPtr = &pidListElems[machPtr->pid];
  534.     }
  535.     /*
  536.      * Move the PID to the end of the PID list and set the hardware PID
  537.      * entry.
  538.      */
  539.     List_Move((List_Links *)pidPtr, LIST_ATREAR(activePIDList));
  540.     VmMachSetPID(machPtr->pid);
  541.  
  542.     MASTER_UNLOCK(vmMachMutexPtr);
  543.     return((ClientData)machPtr->pid);
  544. }
  545.  
  546.  
  547. /*
  548.  * ----------------------------------------------------------------------------
  549.  *
  550.  * Vm_FreeContext --
  551.  *
  552.  *      Release the PID for the current process and flush the TLB for this
  553.  *    PID.
  554.  *
  555.  * Results:
  556.  *      None.
  557.  *
  558.  * Side effects:
  559.  *      PID entry moved from active list to free list and TLB flushed for
  560.  *    the PID.
  561.  *
  562.  * ----------------------------------------------------------------------------
  563.  */
  564. ENTRY void
  565. VmMach_FreeContext(procPtr)
  566.     register    Proc_ControlBlock    *procPtr;
  567. {
  568.     PIDListElem        *pidPtr;
  569.     VmMach_ProcData    *machPtr;
  570.     List_Links        *elemPtr;
  571.     List_Links        *tmpPtr = (List_Links *) NIL;
  572.  
  573.     MASTER_LOCK(vmMachMutexPtr);
  574.  
  575.     machPtr = procPtr->vmPtr->machPtr;
  576.     if (machPtr->pid == VMMACH_INV_PID || machPtr->pid == VMMACH_KERN_PID) {
  577.     machPtr->pid = VMMACH_INV_PID;
  578.     MASTER_UNLOCK(vmMachMutexPtr);
  579.     return;
  580.     }
  581.     pidPtr = &pidListElems[machPtr->pid];
  582.     List_Move((List_Links *)pidPtr, LIST_ATREAR(freePIDList));
  583.     VmMachFlushPIDFromTLB(machPtr->pid);
  584.     TLBHashFlushPID(machPtr->pid);
  585.     machPtr->pid = VMMACH_INV_PID;
  586.     LIST_FORALL(&machPtr->kernSharedList, elemPtr) {
  587.     if (tmpPtr != (List_Links *) NIL) {
  588.         List_Remove(tmpPtr);
  589.         free((char *) tmpPtr);
  590.     }
  591.     tmpPtr = elemPtr;
  592.     }
  593.     if (tmpPtr != (List_Links *) NIL) {
  594.     List_Remove(tmpPtr);
  595.     free((char *) tmpPtr);
  596.     }
  597.     MASTER_UNLOCK(vmMachMutexPtr);
  598. }
  599.  
  600.  
  601. /*
  602.  * ----------------------------------------------------------------------------
  603.  *
  604.  * VmMach_ReinitContext --
  605.  *
  606.  *    Free the current PID and set up another one.  This is called by
  607.  *    routines such as Proc_Exec that add things to the context and
  608.  *    then have to abort or start a process running with a new image.
  609.  *
  610.  * Results:
  611.  *      None.
  612.  *
  613.  * Side effects:
  614.  *      The pid value in the machine dependent VM info for the process.
  615.  *
  616.  * ----------------------------------------------------------------------------
  617.  */
  618. void
  619. VmMach_ReinitContext(procPtr)
  620.     register    Proc_ControlBlock    *procPtr;
  621. {
  622.     VmMach_FreeContext(procPtr);
  623.     (void)VmMach_SetupContext(procPtr);
  624. }
  625.  
  626.  
  627. /*
  628.  *----------------------------------------------------------------------
  629.  *
  630.  * VmMach_VirtAddrParse --
  631.  *
  632.  *    See if the given address falls into the special mapping page.
  633.  *    If so parse it for our caller.
  634.  *
  635.  * Results:
  636.  *    TRUE if the address fell into the special mapping page, FALSE
  637.  *    otherwise.
  638.  *
  639.  * Side effects:
  640.  *    *transVirtAddrPtr may be filled in.
  641.  *
  642.  *----------------------------------------------------------------------
  643.  */
  644. Boolean
  645. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  646.     Proc_ControlBlock        *procPtr;
  647.     Address            virtAddr;
  648.     register    Vm_VirtAddr    *transVirtAddrPtr;
  649. {
  650.     VmMach_ProcData    *machPtr;
  651.  
  652.     if (virtAddr >= (Address)VMMACH_MAPPED_PAGE_ADDR) {
  653.     machPtr = procPtr->vmPtr->machPtr;
  654.     /*
  655.      * The address falls into the special mapping page.  Translate
  656.      * the address back to the segment that it falls into.
  657.      */
  658.     transVirtAddrPtr->segPtr = machPtr->mapSegPtr;
  659.     transVirtAddrPtr->page = machPtr->mappedPage;
  660.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  661.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  662.     transVirtAddrPtr->sharedPtr = (Vm_SegProcList *) machPtr->sharedPtr;
  663.     return(TRUE);
  664.     } else {
  665.     return(FALSE);
  666.     }
  667. }
  668.  
  669.  
  670. /*
  671.  *----------------------------------------------------------------------
  672.  *
  673.  * VmMach_CopyInProc --
  674.  *
  675.  *    Copy from another processes address space into the current address
  676.  *    space.   This is done by mapping the other processes segment into
  677.  *    the current VAS and then doing the copy.  It assumed that this 
  678.  *    routine is called with the source process locked such that its
  679.  *    VM will not go away while we are doing this copy.
  680.  *
  681.  * Results:
  682.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  683.  *
  684.  * Side effects:
  685.  *    What toAddr points to is modified.
  686.  *
  687.  *----------------------------------------------------------------------
  688.  */
  689. /*ARGSUSED*/
  690. ENTRY ReturnStatus
  691. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  692.               toAddr, toKernel)
  693.     int     numBytes;        /* The maximum number of bytes to 
  694.                        copy in. */
  695.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  696.     Address        fromAddr;    /* The address to copy from */
  697.     Vm_VirtAddr        *virtAddrPtr;
  698.     Address        toAddr;        /* The address to copy to */
  699.     Boolean        toKernel;    /* This copy is happening to the
  700.                      * kernel's address space. */
  701. {
  702.     ReturnStatus        status = SUCCESS;
  703.     register VmMach_ProcData    *machPtr;
  704.     Proc_ControlBlock        *toProcPtr;
  705.     int                pageOffset;
  706.     int                bytesToCopy;
  707.  
  708. /*
  709.     printf("VmMach_CopyInProc: num=%x from=%x toAddr=%x toK=%d\n",
  710.         numBytes, fromAddr, toAddr, toKernel);
  711.  */
  712.     toProcPtr = Proc_GetCurrentProc();
  713.     machPtr = toProcPtr->vmPtr->machPtr;
  714.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  715.     machPtr->sharedPtr = (Address) virtAddrPtr->sharedPtr;
  716.     machPtr->mappedPage = (unsigned int) (fromAddr) >> VMMACH_PAGE_SHIFT;
  717.     /*
  718.      * Do a page worths at a time.
  719.      */
  720.     while (numBytes > 0 && status == SUCCESS) {
  721.     pageOffset = (unsigned int)fromAddr & (VMMACH_PAGE_SIZE - 1);
  722.     bytesToCopy = VMMACH_PAGE_SIZE - pageOffset;
  723.     if (bytesToCopy > numBytes) {
  724.         bytesToCopy = numBytes;
  725.     }
  726.     /*
  727.      * Do the copy.
  728.      */
  729.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  730.     status = VmMachDoCopy(bytesToCopy,
  731.                   (Address)(VMMACH_MAPPED_PAGE_ADDR + pageOffset),
  732.                   toAddr);
  733.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  734.  
  735.     MASTER_LOCK(vmMachMutexPtr);
  736.     TLBHashDelete(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  737.     VmMachFlushPageFromTLB(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  738.     MASTER_UNLOCK(vmMachMutexPtr);
  739.  
  740.     if (status == SUCCESS) {
  741.         numBytes -= bytesToCopy;
  742.         fromAddr += bytesToCopy;
  743.         toAddr += bytesToCopy;
  744.     } else {
  745.         status = SYS_ARG_NOACCESS;
  746.     }
  747.     machPtr->mappedPage++;
  748.     }
  749.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  750.     return(status);
  751. }
  752.  
  753.  
  754. /*
  755.  *----------------------------------------------------------------------
  756.  *
  757.  * VmMach_CopyOutProc --
  758.  *
  759.  *    Copy from the current VAS to another processes VAS.  This is done by 
  760.  *    mapping the other processes segment into the current VAS and then 
  761.  *    doing the copy.  It assumed that this routine is called with the dest
  762.  *    process locked such that its VM will not go away while we are doing
  763.  *    the copy.
  764.  *
  765.  * Results:
  766.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  767.  *
  768.  * Side effects:
  769.  *    What toAddr points to is modified.
  770.  *
  771.  *----------------------------------------------------------------------
  772.  */
  773. /*ARGSUSED*/
  774. ENTRY ReturnStatus
  775. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  776.            virtAddrPtr)
  777.     int         numBytes;    /* The maximum number of bytes to 
  778.                        copy in. */
  779.     Address        fromAddr;    /* The address to copy from */
  780.     Boolean        fromKernel;    /* This copy is happening to the
  781.                      * kernel's address space. */
  782.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  783.     Address        toAddr;        /* The address to copy to */
  784.     Vm_VirtAddr        *virtAddrPtr;
  785. {
  786.     ReturnStatus        status = SUCCESS;
  787.     register VmMach_ProcData    *machPtr;
  788.     Proc_ControlBlock        *fromProcPtr;
  789.     int                pageOffset;
  790.     int                bytesToCopy;
  791.  
  792.  
  793. /*
  794.     printf("VmMach_CopyOutProc: num=%x from=%x fromK=%d toAddr=%x\n",
  795.         numBytes, fromAddr, fromKernel, toAddr);
  796.  */
  797.     fromProcPtr = Proc_GetCurrentProc();
  798.     machPtr = fromProcPtr->vmPtr->machPtr;
  799.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  800.     machPtr->mappedPage = (unsigned int) (toAddr) >> VMMACH_PAGE_SHIFT;
  801.     machPtr->sharedPtr = (Address) virtAddrPtr->sharedPtr;
  802.     /*
  803.      * Do a hardware segments worth at a time until done.
  804.      */
  805.     while (numBytes > 0 && status == SUCCESS) {
  806.     pageOffset = (unsigned)toAddr & (VMMACH_PAGE_SIZE - 1);
  807.     bytesToCopy = VMMACH_PAGE_SIZE - pageOffset;
  808.     if (bytesToCopy > numBytes) {
  809.         bytesToCopy = numBytes;
  810.     }
  811.     /*
  812.      * Do the copy.
  813.      */
  814.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  815.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  816.                   (Address) (VMMACH_MAPPED_PAGE_ADDR + pageOffset));
  817.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  818.  
  819.     MASTER_LOCK(vmMachMutexPtr);
  820.     TLBHashDelete(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  821.     VmMachFlushPageFromTLB(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  822.     MASTER_UNLOCK(vmMachMutexPtr);
  823.  
  824.     if (status == SUCCESS) {
  825.         numBytes -= bytesToCopy;
  826.         fromAddr += bytesToCopy;
  827.         toAddr += bytesToCopy;
  828.     } else {
  829.         status = SYS_ARG_NOACCESS;
  830.     }
  831.  
  832.     machPtr->mappedPage++;
  833.     }
  834.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  835.     return(status);
  836. }
  837.  
  838.  
  839. /*
  840.  *----------------------------------------------------------------------
  841.  *
  842.  * VmMach_SetSegProt --
  843.  *
  844.  *    Change the protection in the page table for the given range of bytes
  845.  *    for the given segment.
  846.  *
  847.  * Results:
  848.  *    None.
  849.  *
  850.  * Side effects:
  851.  *    Page table may be modified for the segment.
  852.  *
  853.  *----------------------------------------------------------------------
  854.  */
  855. ENTRY void
  856. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  857.     register Vm_Segment        *segPtr;    /* Segment to change protection
  858.                            for. */
  859.     register int        firstPage;  /* First page to set protection
  860.                          * for. */
  861.     int                lastPage;   /* First page to set protection
  862.                          * for. */
  863.     Boolean            makeWriteable;/* TRUE => make the pages 
  864.                            *     writable.
  865.                            * FALSE => make readable only.*/
  866. {
  867.  
  868.     VmProcLink        *procLinkPtr;
  869.     int            i;
  870.     TLBHashBucket    *bucketPtr;
  871.  
  872.     MASTER_LOCK(vmMachMutexPtr);
  873.  
  874.     if (!makeWriteable || segPtr->type == VM_CODE) {
  875.     VmMachFlushTLB();
  876.     }
  877.  
  878.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  879.     for (i = firstPage; i <= lastPage; i++) {
  880.         bucketPtr= TLBHashFind(procLinkPtr->procPtr->vmPtr->machPtr->pid,
  881.                    (unsigned)i);
  882.         if (bucketPtr != (TLBHashBucket *)NIL) {
  883.         if (makeWriteable) {
  884.             bucketPtr->low |= VMMACH_TLB_ENTRY_WRITEABLE;
  885.         } else {
  886.             bucketPtr->low &= ~VMMACH_TLB_ENTRY_WRITEABLE;
  887.         }
  888. #ifdef notdef
  889.         if (segPtr->type == VM_CODE) {
  890.             bucketPtr->low |= VMMACH_TLB_NON_CACHEABLE_BIT;
  891.         }
  892. #endif
  893.         }
  894.     }
  895.     }
  896.  
  897.     MASTER_UNLOCK(vmMachMutexPtr);
  898. }
  899.  
  900.  
  901. /*
  902.  *----------------------------------------------------------------------
  903.  *
  904.  * VmMach_FlushCode --
  905.  *
  906.  *    Flush the specified address range from the instruction cache.
  907.  *
  908.  * Results:
  909.  *    None.
  910.  *
  911.  * Side effects:
  912.  *    Code is flushed from the cache.
  913.  *
  914.  *----------------------------------------------------------------------
  915.  */
  916. /*ARGSUSED*/
  917. void
  918. VmMach_FlushCode(procPtr, virtAddrPtr, physPage, numBytes)
  919.     Proc_ControlBlock    *procPtr;
  920.     Vm_VirtAddr        *virtAddrPtr;
  921.     unsigned        physPage;
  922.     int            numBytes;
  923. {
  924.     Mach_FlushCode((Address)((physPage << VMMACH_PAGE_SHIFT) +
  925.         virtAddrPtr->offset), (unsigned)numBytes);
  926. }
  927.  
  928.  
  929. /*
  930.  *----------------------------------------------------------------------
  931.  *
  932.  * VmMach_SetPageProt --
  933.  *
  934.  *    Set the protection in hardware and software for the given virtual
  935.  *    page.  
  936.  *
  937.  *    IMPORTANT: We assume that we have access to the list of processes
  938.  *           that are using this segment (i.e. the caller has the
  939.  *           virtual memory monitor lock down).
  940.  *
  941.  * Results:
  942.  *    None.
  943.  *
  944.  * Side effects:
  945.  *    Page table may be modified for the segment.
  946.  *
  947.  *----------------------------------------------------------------------
  948.  */
  949. ENTRY void
  950. VmMach_SetPageProt(virtAddrPtr, softPTE)
  951.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  952.                          * protection for.*/
  953.     Vm_PTE            softPTE;    /* Software pte. */
  954. {
  955.     Vm_Segment        *segPtr;
  956.     VmProcLink        *procLinkPtr;
  957.     int            pid;
  958.     TLBHashBucket    *bucketPtr;
  959.  
  960.     MASTER_LOCK(vmMachMutexPtr);
  961.  
  962.     segPtr = virtAddrPtr->segPtr;
  963.     if (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) {
  964.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  965.         pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  966.         (void) VmMachClearTLBModBit(pid, virtAddrPtr->page);
  967.         bucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  968.         if (bucketPtr != (TLBHashBucket *)NIL) {
  969.         bucketPtr->low &= ~VMMACH_TLB_MOD_BIT;
  970.         }
  971.         bucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  972.         if (bucketPtr != (TLBHashBucket *)NIL) {
  973.         bucketPtr->low &= ~VMMACH_TLB_ENTRY_WRITEABLE;
  974.         }
  975.     }
  976.     } else {
  977.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  978.         bucketPtr = TLBHashFind(procLinkPtr->procPtr->vmPtr->machPtr->pid,
  979.                     (unsigned)virtAddrPtr->page);
  980.         if (bucketPtr != (TLBHashBucket *)NIL) {
  981.         bucketPtr->low |= VMMACH_TLB_ENTRY_WRITEABLE;
  982.         }
  983.     }
  984.     }
  985.  
  986.     MASTER_UNLOCK(vmMachMutexPtr);
  987. }
  988.  
  989.  
  990. /*
  991.  * ----------------------------------------------------------------------------
  992.  *
  993.  * VmMach_AllocCheck --
  994.  *
  995.  *      Determine if this page can be reallocated.  A page can be reallocated
  996.  *    if it has not been referenced or modified.
  997.  *  
  998.  * Results:
  999.  *      None.
  1000.  *
  1001.  * Side effects:
  1002.  *      The given page will be invalidated in the hardware if it has not
  1003.  *    been referenced and *refPtr and *modPtr will have the hardware 
  1004.  *    reference and modify bits or'd in.
  1005.  *
  1006.  * ----------------------------------------------------------------------------
  1007.  */
  1008. ENTRY void
  1009. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  1010.     register    Vm_VirtAddr    *virtAddrPtr;
  1011.     unsigned    int        virtFrameNum;
  1012.     register    Boolean        *refPtr;
  1013.     register    Boolean        *modPtr;
  1014. {
  1015.     Boolean    origMod;
  1016.  
  1017.     MASTER_LOCK(vmMachMutexPtr);
  1018.  
  1019.     origMod = *modPtr;
  1020.  
  1021.     *refPtr |= vmMachPhysPageArr[virtFrameNum].referenced;
  1022.     *modPtr = vmMachPhysPageArr[virtFrameNum].modified;
  1023.     if (!*refPtr) {
  1024.     /*
  1025.      * Invalidate the page so that it will force a fault if it is
  1026.      * referenced.  Since our caller has blocked all faults on this
  1027.      * page, by invalidating it we can guarantee that the reference and
  1028.      * modify information that we are returning will be valid until
  1029.      * our caller reenables faults on this page.
  1030.      */
  1031.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  1032.  
  1033.     if (origMod && !*modPtr) {
  1034.         /*
  1035.          * This page had the modify bit set in software but not in
  1036.          * hardware.
  1037.          */
  1038.         vmStat.notHardModPages++;
  1039.     }
  1040.     }
  1041.     *modPtr |= origMod;
  1042.  
  1043.     MASTER_UNLOCK(vmMachMutexPtr);
  1044. }
  1045.  
  1046.  
  1047. /*
  1048.  * ----------------------------------------------------------------------------
  1049.  *
  1050.  * VmMach_GetRefModBits --
  1051.  *
  1052.  *      Pull the reference and modified bits out of hardware.
  1053.  *  
  1054.  * Results:
  1055.  *      None.
  1056.  *
  1057.  * Side effects:
  1058.  *      
  1059.  *
  1060.  * ----------------------------------------------------------------------------
  1061.  */
  1062. /*ARGSUSED*/
  1063. ENTRY void
  1064. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  1065.     Vm_VirtAddr            *virtAddrPtr;
  1066.     unsigned    int        virtFrameNum;
  1067.     register    Boolean        *refPtr;
  1068.     register    Boolean        *modPtr;
  1069. {
  1070.     MASTER_LOCK(vmMachMutexPtr);
  1071.  
  1072.     *refPtr = vmMachPhysPageArr[virtFrameNum].referenced;
  1073.     *modPtr = vmMachPhysPageArr[virtFrameNum].modified;
  1074.  
  1075.     MASTER_UNLOCK(vmMachMutexPtr);
  1076. }
  1077.  
  1078.  
  1079. /*
  1080.  * ----------------------------------------------------------------------------
  1081.  *
  1082.  * VmMach_ClearRefBit --
  1083.  *
  1084.  *      Clear the reference bit at the given virtual address.
  1085.  *
  1086.  * Results:
  1087.  *      None.
  1088.  *
  1089.  * Side effects:
  1090.  *      Hardware reference bit cleared.
  1091.  *
  1092.  * ----------------------------------------------------------------------------
  1093.  */
  1094. /*ARGSUSED*/
  1095. ENTRY void
  1096. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  1097.     Vm_VirtAddr        *virtAddrPtr;
  1098.     unsigned     int    virtFrameNum;
  1099. {
  1100.     MASTER_LOCK(vmMachMutexPtr);
  1101.  
  1102.     vmMachPhysPageArr[virtFrameNum].referenced = 0;
  1103.  
  1104.     MASTER_UNLOCK(vmMachMutexPtr);
  1105. }
  1106.  
  1107.  
  1108. /*
  1109.  * ----------------------------------------------------------------------------
  1110.  *
  1111.  * VmMach_ClearModBit --
  1112.  *
  1113.  *      Clear the modified bit at the given virtual address.
  1114.  *
  1115.  * Results:
  1116.  *      None.
  1117.  *
  1118.  * Side effects:
  1119.  *      Hardware modified bit cleared.
  1120.  *
  1121.  * ----------------------------------------------------------------------------
  1122.  */
  1123. ENTRY void
  1124. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  1125.     register    Vm_VirtAddr    *virtAddrPtr;
  1126.     unsigned    int        virtFrameNum;
  1127. {
  1128.     register    Vm_Segment    *segPtr;
  1129.     VmProcLink            *procLinkPtr;
  1130.     int                pid;
  1131.     TLBHashBucket        *hashBucketPtr;
  1132.  
  1133.     MASTER_LOCK(vmMachMutexPtr);
  1134.  
  1135.     vmMachPhysPageArr[virtFrameNum].modified = 0;
  1136.  
  1137.     segPtr = virtAddrPtr->segPtr;
  1138.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  1139.     pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  1140.     (void) VmMachClearTLBModBit(pid, virtAddrPtr->page);
  1141.     hashBucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  1142.     if (hashBucketPtr != (TLBHashBucket *)NIL) {
  1143.         hashBucketPtr->low &= ~VMMACH_TLB_MOD_BIT;
  1144.     }
  1145.     }
  1146.  
  1147.     MASTER_UNLOCK(vmMachMutexPtr);
  1148. }
  1149.  
  1150.  
  1151. /*
  1152.  * ----------------------------------------------------------------------------
  1153.  *
  1154.  * VmMach_PageValidate --
  1155.  *
  1156.  *      Validate a page for the given virtual address.  It is assumed that when
  1157.  *      this routine is called that the pid register contains the pid in which
  1158.  *    this page will be validated.
  1159.  *
  1160.  * Results:
  1161.  *      None.
  1162.  *
  1163.  * Side effects:
  1164.  *      The page table and hardware segment tables associated with the segment
  1165.  *      are modified to validate the page.
  1166.  *
  1167.  * ----------------------------------------------------------------------------
  1168.  */
  1169. ENTRY void
  1170. VmMach_PageValidate(virtAddrPtr, pte) 
  1171.     register    Vm_VirtAddr    *virtAddrPtr;
  1172.     Vm_PTE            pte;
  1173. {
  1174.     Proc_ControlBlock    *procPtr;
  1175.     VmMach_ProcData    *machPtr;
  1176.     unsigned        lowEntry;
  1177.     unsigned        virtPage;
  1178.     int            retVal;
  1179.     int            page;
  1180.  
  1181.     MASTER_LOCK(vmMachMutexPtr);
  1182.  
  1183.     procPtr = Proc_GetCurrentProc();
  1184.     machPtr = procPtr->vmPtr->machPtr;
  1185.     if (machPtr->pid == 0) {
  1186.     VmMach_ReinitContext(procPtr);
  1187.     }
  1188.  
  1189.     /*
  1190.      * Set up the TLB entry and the physical page info.
  1191.      */
  1192.     if (virtAddrPtr->segPtr == vm_SysSegPtr) {
  1193.     lowEntry = ((pte & VM_PAGE_FRAME_FIELD) << VMMACH_TLB_PHYS_PAGE_SHIFT)| 
  1194.             VMMACH_TLB_VALID_BIT | VMMACH_TLB_GLOBAL_BIT | 
  1195.             VMMACH_TLB_MOD_BIT;
  1196.     retVal = VmMachWriteTLB(lowEntry,
  1197.           (unsigned) ((virtAddrPtr->page << VMMACH_TLB_VIRT_PAGE_SHIFT) | 
  1198.                (VMMACH_KERN_PID << VMMACH_TLB_PID_SHIFT)));
  1199.     if (retVal >= 0) {
  1200.         panic("VmMach_PageValidate: Kern TLB entry found\n");
  1201.     }
  1202.     page = virtAddrPtr->page - VMMACH_VIRT_CACHED_START_PAGE;
  1203.     if (page >= 0) {
  1204.         vmMach_KernelTLBMap[page] = lowEntry;
  1205.     }
  1206.     } else {
  1207.     unsigned    highEntry;
  1208.     Boolean        shared = FALSE;
  1209.     VmMach_KernSharedInfo    *infoPtr = (VmMach_KernSharedInfo *) NIL
  1210.     ;
  1211.  
  1212.     if (!List_IsEmpty(&machPtr->kernSharedList)) {
  1213.         LIST_FORALL(&machPtr->kernSharedList, (List_Links *) infoPtr) {
  1214.         if ((virtAddrPtr->page >= infoPtr->firstPage) &&
  1215.             (virtAddrPtr->page <= infoPtr->lastPage)) {
  1216.             shared = TRUE;
  1217.             List_Move((List_Links *) infoPtr, 
  1218.             LIST_ATFRONT(&machPtr->kernSharedList));
  1219.         }
  1220.         }
  1221.     }
  1222.     if ((pte & VM_PAGE_FRAME_FIELD) < vm_NumPhysPages) {
  1223.         vmMachPhysPageArr[pte & VM_PAGE_FRAME_FIELD].user = 1;
  1224.     }
  1225.     lowEntry = ((pte & VM_PAGE_FRAME_FIELD) << 
  1226.                 VMMACH_TLB_PHYS_PAGE_SHIFT) | 
  1227.             VMMACH_TLB_VALID_BIT;
  1228.     if (!(pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) && !(virtAddrPtr->flags
  1229.         & VM_READONLY_SEG)) {
  1230.         lowEntry |= VMMACH_TLB_ENTRY_WRITEABLE;
  1231.     }
  1232.     if (shared) {
  1233.         lowEntry |= VMMACH_TLB_MOD_BIT;
  1234.         if (infoPtr->flags & VMMACH_KERN_SHARED_UNCACHEABLE) {
  1235.         lowEntry |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1236.         }
  1237.     }
  1238.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  1239.         virtPage = VMMACH_MAPPED_PAGE_NUM;
  1240.     } else {
  1241.         virtPage = virtAddrPtr->page;
  1242.     }
  1243.     if (machPtr->modPage == virtPage) {
  1244.         /*
  1245.          * We are validating after a TLB modified fault so set the modify
  1246.          * bit.
  1247.          */
  1248.         lowEntry |= VMMACH_TLB_MOD_BIT;
  1249.         vmMachPhysPageArr[pte & VM_PAGE_FRAME_FIELD].modified = 1;
  1250.     }
  1251.  
  1252.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1253.             (machPtr->pid << VMMACH_TLB_PID_SHIFT);
  1254.     TLBHashInsert(machPtr->pid, virtPage, lowEntry, highEntry);
  1255.     retVal = VmMachWriteTLB(lowEntry, highEntry);
  1256.     if (retVal >= 0 && !(machPtr->modPage == virtPage)) {
  1257.         panic("VmMach_PageValidate: Non-modified user TLB entry found\n");
  1258.     }
  1259.     }
  1260.  
  1261.     MASTER_UNLOCK(vmMachMutexPtr);
  1262. }
  1263.  
  1264.  
  1265. /*
  1266.  * ----------------------------------------------------------------------------
  1267.  *
  1268.  * PageInvalidate --
  1269.  *
  1270.  *      Invalidate a page for the given segment.  
  1271.  *
  1272.  * Results:
  1273.  *      None.
  1274.  *
  1275.  * Side effects:
  1276.  *      The page table and hardware tables associated with the segment
  1277.  *      are modified to invalidate the page.
  1278.  *
  1279.  * ----------------------------------------------------------------------------
  1280.  */
  1281. /*ARGSUSED*/
  1282. INTERNAL static void
  1283. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  1284.     register    Vm_VirtAddr    *virtAddrPtr;
  1285.     unsigned     int        virtPage;
  1286.     Boolean            segDeletion;
  1287. {
  1288.     PhysPage        *physPagePtr;
  1289.  
  1290.     physPagePtr = &vmMachPhysPageArr[virtPage];
  1291.     if ((physPagePtr->user && virtAddrPtr->segPtr != vm_SysSegPtr) ||
  1292.         !physPagePtr->user) {
  1293.     /*
  1294.      * Clear out reference and modified info for this page.  We can
  1295.      * only clear it if one of two conditions hold:
  1296.      *
  1297.      *    1) It has been validated in a user's address space and
  1298.      *       is now being invalidated from a user's address space.
  1299.      *    2) It has never been validated in a user's address space.
  1300.      *
  1301.      * We have to make this distinction because a page can be mapped
  1302.      * both by a user and the kernel at the same time and we need to
  1303.      * make sure that the kernel invalidation doesn't wipe out good
  1304.      * user reference and modify information.
  1305.      */
  1306.     physPagePtr->user = 0;
  1307.     physPagePtr->referenced = 0;
  1308.     physPagePtr->modified = 0;
  1309.     }
  1310.  
  1311.     if (virtAddrPtr->segPtr == vm_SysSegPtr) {
  1312.     int    page;
  1313.  
  1314.     page = virtAddrPtr->page - VMMACH_VIRT_CACHED_START_PAGE;
  1315.     if (page >= 0) {
  1316.         vmMach_KernelTLBMap[page] = 0;
  1317.     }
  1318.     (void) VmMachFlushPageFromTLB(VMMACH_KERN_PID, 
  1319.                       (unsigned)virtAddrPtr->page);
  1320.     } else {
  1321.     VmProcLink    *procLinkPtr;
  1322.     int        pid;
  1323.  
  1324.     /*
  1325.      * Flush the page from all pids.
  1326.      */
  1327.     LIST_FORALL(virtAddrPtr->segPtr->procList, (List_Links *) procLinkPtr) {
  1328.         pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  1329.         (void) VmMachFlushPageFromTLB(pid, (unsigned)virtAddrPtr->page);
  1330.         TLBHashDelete(pid, (unsigned)virtAddrPtr->page);
  1331.     }
  1332.     if (virtAddrPtr->segPtr->type == VM_CODE) {
  1333.         /*
  1334.          * If a code page flush it from the instruction cache.
  1335.          */
  1336.         Mach_FlushCode((Address)(virtPage << VMMACH_PAGE_SHIFT),
  1337.             VMMACH_PAGE_SIZE);
  1338.     }
  1339.     }
  1340. }
  1341.  
  1342.  
  1343. /*
  1344.  * ----------------------------------------------------------------------------
  1345.  *
  1346.  * VmMach_PageInvalidate --
  1347.  *
  1348.  *      Invalidate a page for the given segment.  
  1349.  *
  1350.  * Results:
  1351.  *      None.
  1352.  *
  1353.  * Side effects:
  1354.  *      The page table and hardware segment tables associated with the segment
  1355.  *      are modified to invalidate the page.
  1356.  *
  1357.  * ----------------------------------------------------------------------------
  1358.  */
  1359. ENTRY void
  1360. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  1361.     register    Vm_VirtAddr    *virtAddrPtr;
  1362.     unsigned     int        virtPage;
  1363.     Boolean            segDeletion;
  1364. {
  1365.     MASTER_LOCK(vmMachMutexPtr);
  1366.  
  1367.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  1368.  
  1369.     MASTER_UNLOCK(vmMachMutexPtr);
  1370. }
  1371.  
  1372.  
  1373. /*
  1374.  *----------------------------------------------------------------------
  1375.  *
  1376.  * VmMach_PinUserPages --
  1377.  *
  1378.  *    Force a user page to be resident in memory.
  1379.  *
  1380.  * Results:
  1381.  *    None.
  1382.  *
  1383.  * Side effects:
  1384.  *    None.
  1385.  *
  1386.  *----------------------------------------------------------------------
  1387.  */
  1388. /*ARGSUSED*/
  1389. void
  1390. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  1391.     int        mapType;
  1392.     Vm_VirtAddr    *virtAddrPtr;
  1393.     int        lastPage;
  1394. {
  1395. }
  1396.  
  1397.  
  1398. /*
  1399.  *----------------------------------------------------------------------
  1400.  *
  1401.  * VmMach_UnpinUserPages --
  1402.  *
  1403.  *    Allow a page that was pinned to be unpinned.
  1404.  *
  1405.  * Results:
  1406.  *    None.
  1407.  *
  1408.  * Side effects:
  1409.  *    None.
  1410.  *
  1411.  *----------------------------------------------------------------------
  1412.  */
  1413. /*ARGSUSED*/
  1414. ENTRY void
  1415. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  1416.     Vm_VirtAddr    *virtAddrPtr;
  1417.     int        lastPage;
  1418. {
  1419. }
  1420.  
  1421.  
  1422. /*
  1423.  *----------------------------------------------------------------------
  1424.  *
  1425.  * VmMach_FlushPage --
  1426.  *
  1427.  *    Flush the page at the given virtual address from all caches.  We
  1428.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  1429.  *    that we have.
  1430.  *
  1431.  * Results:
  1432.  *    None.
  1433.  *
  1434.  * Side effects:
  1435.  *    The given page is flushed from the caches.
  1436.  *
  1437.  *----------------------------------------------------------------------
  1438.  */
  1439. /*ARGSUSED*/
  1440. void
  1441. VmMach_FlushPage(virtAddrPtr, invalidate)
  1442.     Vm_VirtAddr    *virtAddrPtr;
  1443.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  1444. {
  1445. }
  1446.  
  1447.  
  1448. /*
  1449.  *----------------------------------------------------------------------
  1450.  *
  1451.  * VmMach_HandleSegMigration --
  1452.  *
  1453.  *    Handle machine-dependent aspects of segment preparation for migration.
  1454.  *    There's nothing to do on this machine.
  1455.  *
  1456.  * Results:
  1457.  *    None.
  1458.  *
  1459.  * Side effects:
  1460.  *    None.
  1461.  *
  1462.  *----------------------------------------------------------------------
  1463.  */
  1464. /*ARGSUSED*/
  1465. void
  1466. VmMach_HandleSegMigration(segPtr)
  1467.     Vm_Segment    *segPtr;
  1468. {
  1469.     return;
  1470. }
  1471.  
  1472.  
  1473.  
  1474. /*
  1475.  *----------------------------------------------------------------------
  1476.  *
  1477.  * VmMach_Cmd --
  1478.  *
  1479.  *    Machine dependent vm commands.
  1480.  *
  1481.  * Results:
  1482.  *    None.
  1483.  *
  1484.  * Side effects:
  1485.  *    None.
  1486.  *
  1487.  *----------------------------------------------------------------------
  1488.  */
  1489. /*ARGSUSED*/
  1490. ReturnStatus
  1491. VmMach_Cmd(command, arg)
  1492.     int    command;
  1493.     int arg;
  1494. {
  1495.     return(GEN_INVALID_ARG);
  1496. }
  1497.  
  1498.  
  1499.  
  1500. /*
  1501.  *----------------------------------------------------------------------
  1502.  *
  1503.  * VmMach_TLBFault --
  1504.  *
  1505.  *    Handle a TLB fault.
  1506.  *
  1507.  * Results:
  1508.  *    None.
  1509.  *
  1510.  * Side effects:
  1511.  *    None.
  1512.  *
  1513.  *----------------------------------------------------------------------
  1514.  */
  1515. ENTRY ReturnStatus
  1516. VmMach_TLBFault(virtAddr)
  1517.     Address    virtAddr;
  1518. {
  1519.  
  1520.     if (virtAddr >= (Address)VMMACH_VIRT_CACHED_START &&
  1521.         virtAddr < (Address)VMMACH_MAPPED_PAGE_ADDR) {
  1522.     dprintf("fault 1\n");
  1523.     return(FAILURE);
  1524.     } else if (virtAddr >= (Address)VMMACH_USER_MAPPING_BASE_ADDR &&
  1525.            virtAddr < (Address)VMMACH_PHYS_CACHED_START) {
  1526.     /*
  1527.      * This address falls into the range of address that are used to
  1528.      * map kernel pages into a user's address space.
  1529.      */
  1530.     unsigned         virtPage, lowEntry, highEntry;
  1531.     int             pid;
  1532.     VmMach_ProcData        *machPtr;
  1533.     Proc_ControlBlock    *procPtr;
  1534.     Boolean            found = FALSE;
  1535.     VmMach_KernSharedInfo    *infoPtr;
  1536.  
  1537.     procPtr = Proc_GetCurrentProc();
  1538.     machPtr = procPtr->vmPtr->machPtr;
  1539.     pid = procPtr->vmPtr->machPtr->pid;
  1540.     virtPage = (unsigned)virtAddr >> VMMACH_PAGE_SHIFT;
  1541.     LIST_FORALL(&machPtr->kernSharedList, (List_Links *) infoPtr) {
  1542.         if ((virtPage >= infoPtr->firstPage) &&
  1543.         (virtPage <= infoPtr->lastPage)) {
  1544.         found = TRUE;
  1545.         List_Move((List_Links *) infoPtr, 
  1546.             LIST_ATFRONT(&machPtr->kernSharedList));
  1547.         break;
  1548.         }
  1549.     }
  1550.     if (!found) {
  1551.         return FALSE;
  1552.     }
  1553.     lowEntry = (virtPage - infoPtr->firstPage + infoPtr->firstPhysPage) <<
  1554.             VMMACH_TLB_PHYS_PAGE_SHIFT;
  1555.     lowEntry |= VMMACH_TLB_VALID_BIT | VMMACH_TLB_MOD_BIT;
  1556.     if (infoPtr->flags & VMMACH_KERN_SHARED_UNCACHEABLE) {
  1557.         lowEntry |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1558.     }
  1559.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1560.             (pid << VMMACH_TLB_PID_SHIFT);
  1561.  
  1562.     MASTER_LOCK(vmMachMutexPtr);
  1563.     TLBHashInsert(pid, virtPage, lowEntry, highEntry);
  1564.     (void)VmMachWriteTLB(lowEntry, highEntry);
  1565.     MASTER_UNLOCK(vmMachMutexPtr);
  1566.  
  1567.     return(SUCCESS);
  1568.     } else {
  1569.     ReturnStatus status;
  1570.     status = Vm_PageIn(virtAddr, FALSE);
  1571.     if (status != SUCCESS) {
  1572.         dprintf("fault 4\n");
  1573.     }
  1574.     return status;
  1575.     /*
  1576.     return(Vm_PageIn(virtAddr, FALSE));
  1577.     */
  1578.     }
  1579. }
  1580.  
  1581.  
  1582. /*
  1583.  *----------------------------------------------------------------------
  1584.  *
  1585.  * VmMach_TLBModFault --
  1586.  *
  1587.  *    Handle a TLB modify fault.
  1588.  *
  1589.  * Results:
  1590.  *    None.
  1591.  *
  1592.  * Side effects:
  1593.  *    None.
  1594.  *
  1595.  *----------------------------------------------------------------------
  1596.  */
  1597. ReturnStatus
  1598. VmMach_TLBModFault(virtAddr)
  1599.     Address    virtAddr;
  1600. {
  1601.     Proc_ControlBlock        *procPtr;
  1602.     ReturnStatus        status;
  1603.  
  1604.     if (virtAddr >= (Address)VMMACH_VIRT_CACHED_START &&
  1605.     virtAddr < (Address)VMMACH_MAPPED_PAGE_ADDR) {
  1606.     /*
  1607.      * We shouldn't get TLB modified faults for kernel virtual
  1608.      * addresses because the modify bit was set when we validated the 
  1609.      * page.
  1610.      */
  1611.     panic("VmMach_TLBModFault: Kernel TLB mod fault\n");
  1612.     return(FAILURE);
  1613.     }
  1614.     tlbCountersPtr->slowModCount++;
  1615.     procPtr = Proc_GetCurrentProc();
  1616.     procPtr->vmPtr->machPtr->modPage = (unsigned)virtAddr >> VMMACH_PAGE_SHIFT;
  1617.     status = Vm_PageIn(virtAddr, TRUE);
  1618.     procPtr->vmPtr->machPtr->modPage = 0;
  1619.     return(status);
  1620. }
  1621.  
  1622.  
  1623. /*
  1624.  *----------------------------------------------------------------------
  1625.  *
  1626.  * VmMach_MapKernelIntoUser --
  1627.  *
  1628.  *    Unimplemented on PMAX.
  1629.  *
  1630.  * Results:
  1631.  *    FAILURE.
  1632.  *
  1633.  * Side effects:
  1634.  *    None.
  1635.  *
  1636.  *----------------------------------------------------------------------
  1637.  */
  1638. ReturnStatus
  1639. VmMach_MapKernelIntoUser()
  1640. {
  1641.     return(FAILURE);
  1642. }
  1643.  
  1644.  
  1645. /*
  1646.  *----------------------------------------------------------------------
  1647.  *
  1648.  * VmMach_Trace --
  1649.  *
  1650.  *    Virtual memory tracing.
  1651.  *
  1652.  * Results:
  1653.  *    None.
  1654.  *
  1655.  * Side effects:
  1656.  *    None.
  1657.  *
  1658.  *----------------------------------------------------------------------
  1659.  */
  1660. void
  1661. VmMach_Trace()
  1662. {
  1663. }
  1664.  
  1665.  
  1666. /*
  1667.  *----------------------------------------------------------------------
  1668.  *
  1669.  * VmMach_MakeDebugAccessible --
  1670.  *
  1671.  *    Make the given address accessible for the debugger.
  1672.  *
  1673.  * Results:
  1674.  *    TRUE if could make accessible, FALSE if couldn't.
  1675.  *
  1676.  * Side effects:
  1677.  *    None.
  1678.  *
  1679.  *----------------------------------------------------------------------
  1680.  */
  1681. Boolean
  1682. VmMach_MakeDebugAccessible(addr)
  1683.     unsigned    addr;
  1684. {
  1685.     unsigned virtPage, lowEntry, highEntry;
  1686.     static int allowIOSpace = FALSE;
  1687.  
  1688.     if (addr < (unsigned)VMMACH_VIRT_CACHED_START) {
  1689.     if (addr < (unsigned)VMMACH_PHYS_UNCACHED_START) {
  1690.         if ((addr < (unsigned)VMMACH_PHYS_CACHED_START + 
  1691.             vm_NumPhysPages * VMMACH_PAGE_SIZE) &&
  1692.         (addr >= (unsigned)VMMACH_PHYS_CACHED_START)) {
  1693.         return TRUE;
  1694.         } else {
  1695.         return FALSE;
  1696.         }
  1697.     } else {
  1698.         if (addr < (unsigned)VMMACH_PHYS_UNCACHED_START + 
  1699.             vm_NumPhysPages * VMMACH_PAGE_SIZE) {
  1700.         return TRUE;
  1701.         } else if (allowIOSpace) {
  1702.         if ((addr < (unsigned) MACH_IO_SLOT_ADDR(7)) &&
  1703.                 (addr >= (unsigned) MACH_IO_SLOT_ADDR(5))) {
  1704.             return TRUE;
  1705.         } else if ((addr < (unsigned) MACH_IO_SLOT_ADDR(3)) &&
  1706.                 (addr >= (unsigned) MACH_IO_SLOT_ADDR(0))) {
  1707.             return TRUE;
  1708.         } else {
  1709.             return FALSE;
  1710.         }
  1711.         }
  1712.     }
  1713.     }
  1714.     if (addr > (unsigned)mach_KernEnd) {
  1715.     return(FALSE);
  1716.     }
  1717.     virtPage = addr >> VMMACH_PAGE_SHIFT;
  1718.     lowEntry = vmMach_KernelTLBMap[virtPage - VMMACH_VIRT_CACHED_START_PAGE];
  1719.     if (lowEntry == 0) {
  1720.     return(FALSE);
  1721.     }
  1722.     /*
  1723.      * Use the special reserved TLB entry (entry 0).
  1724.      */
  1725.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1726.                 (VMMACH_KERN_PID << VMMACH_TLB_PID_SHIFT);
  1727.     VmMachWriteIndexedTLB(0, lowEntry, highEntry);
  1728.     return(TRUE);
  1729. }
  1730.  
  1731. #define TLB_HASH(pid, page) \
  1732.     ((page) ^ ((pid) << (VMMACH_PID_HASH_SHIFT + VMMACH_TLB_PID_SHIFT - \
  1733.              VMMACH_BUCKET_SIZE_SHIFT))) & VMMACH_HASH_MASK_2
  1734.  
  1735.  
  1736. /*
  1737.  *----------------------------------------------------------------------
  1738.  *
  1739.  * TLBHashFind --
  1740.  *
  1741.  *    Find the entry with the given key in the hash table.
  1742.  *
  1743.  * Results:
  1744.  *    Pointer to hash table entry if found, NIL otherwise.
  1745.  *
  1746.  * Side effects:
  1747.  *    None.
  1748.  *
  1749.  *----------------------------------------------------------------------
  1750.  */
  1751. INTERNAL static TLBHashBucket *
  1752. TLBHashFind(pid, page)
  1753.     int        pid;
  1754.     unsigned    page;
  1755. {
  1756.     TLBHashBucket    *hashBucketPtr;
  1757.  
  1758.     tlbCountersPtr->numProbes++;
  1759.  
  1760.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1761.     if (hashBucketPtr->high == ((page << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1762.                 (pid << VMMACH_TLB_PID_SHIFT))) {
  1763.     tlbCountersPtr->numFound++;
  1764.     return(hashBucketPtr);
  1765.     } else {
  1766.     return((TLBHashBucket *)NIL);
  1767.     }
  1768. }
  1769.  
  1770.  
  1771. /*
  1772.  *----------------------------------------------------------------------
  1773.  *
  1774.  * TLBHashDelete --
  1775.  *
  1776.  *    Find the entry with the given key in the hash table and delete it.
  1777.  *
  1778.  * Results:
  1779.  *    None.
  1780.  *
  1781.  * Side effects:
  1782.  *    Entry may be deleted from the hash table.
  1783.  *
  1784.  *----------------------------------------------------------------------
  1785.  */
  1786. INTERNAL static void
  1787. TLBHashDelete(pid, page)
  1788.     int        pid;
  1789.     unsigned    page;
  1790. {
  1791.     TLBHashBucket    *hashBucketPtr;
  1792.  
  1793.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1794.     if (hashBucketPtr->high == ((page << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1795.                 (pid << VMMACH_TLB_PID_SHIFT))) {
  1796.     hashBucketPtr->high = 0;
  1797.     List_Remove((List_Links *)hashBucketPtr);
  1798.     }
  1799. }
  1800.  
  1801.  
  1802. /*
  1803.  *----------------------------------------------------------------------
  1804.  *
  1805.  * TLBHashInsert --
  1806.  *
  1807.  *    Insert the entry in the hash table if it is not already there.
  1808.  *
  1809.  * Results:
  1810.  *    None.
  1811.  *
  1812.  * Side effects:
  1813.  *    Entry may be added to the hash table.
  1814.  *
  1815.  *----------------------------------------------------------------------
  1816.  */
  1817. INTERNAL static void
  1818. TLBHashInsert(pid, page, lowReg, hiReg)
  1819.     int        pid;
  1820.     unsigned    page;
  1821.     unsigned    lowReg;
  1822.     unsigned    hiReg;
  1823. {
  1824.     TLBHashBucket    *hashBucketPtr;
  1825.  
  1826.     if (pid == VMMACH_KERN_PID) {
  1827.     /*
  1828.      * Don't insert any entries for the kernel pid.  This will only 
  1829.      * happen because a process with no VM is doing a CopyOutProc.
  1830.      */
  1831.     return;
  1832.     }
  1833.  
  1834.     tlbCountersPtr->numInserts++;
  1835.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1836.     if (hashBucketPtr->high == hiReg) {
  1837.     return;
  1838.     }
  1839.     if (hashBucketPtr->high != 0) {
  1840.     tlbCountersPtr->numCollisions++;
  1841.     List_Remove((List_Links *)hashBucketPtr);
  1842.     }
  1843.     hashBucketPtr->low = lowReg;
  1844.     hashBucketPtr->high = hiReg;
  1845.     List_Insert((List_Links *)hashBucketPtr,
  1846.         LIST_ATREAR(&pidListElems[pid].tlbList));
  1847. }
  1848.  
  1849.  
  1850. /*
  1851.  *----------------------------------------------------------------------
  1852.  *
  1853.  * TLBHashFlushPID --
  1854.  *
  1855.  *    Flush all entries for the given PID from the hash table.
  1856.  *
  1857.  * Results:
  1858.  *    None.
  1859.  *
  1860.  * Side effects:
  1861.  *    All entries for the given PID are flushed from the hash table.
  1862.  *
  1863.  *----------------------------------------------------------------------
  1864.  */
  1865. INTERNAL static void
  1866. TLBHashFlushPID(pid)
  1867.     int    pid;
  1868. {
  1869.     PIDListElem        *pidPtr;
  1870.     TLBHashBucket    *hashBucketPtr;
  1871.  
  1872.     pidPtr = &pidListElems[pid];
  1873.     while (!List_IsEmpty(&pidPtr->tlbList)) {
  1874.     hashBucketPtr = (TLBHashBucket *)List_First(&pidPtr->tlbList);
  1875.     List_Remove((List_Links *)hashBucketPtr);
  1876.     hashBucketPtr->high = 0;
  1877.     }
  1878. }
  1879.  
  1880.  
  1881. /*
  1882.  *----------------------------------------------------------------------
  1883.  *
  1884.  * VmMach_MakeNonCacheable --
  1885.  *
  1886.  *    Make the given page non-cacheable.
  1887.  *
  1888.  * Results:
  1889.  *    None.
  1890.  *
  1891.  * Side effects:
  1892.  *    None.
  1893.  *
  1894.  *----------------------------------------------------------------------
  1895.  */
  1896. ENTRY void
  1897. VmMach_MakeNonCacheable(procPtr, addr)
  1898.     Proc_ControlBlock    *procPtr;
  1899.     Address        addr;
  1900. {
  1901.     TLBHashBucket    *bucketPtr;
  1902.  
  1903.     MASTER_LOCK(vmMachMutexPtr);
  1904.  
  1905.     VmMachFlushTLB();
  1906.     bucketPtr = TLBHashFind(procPtr->vmPtr->machPtr->pid,
  1907.                 (unsigned)addr >> VMMACH_PAGE_SHIFT);
  1908.     if (bucketPtr != (TLBHashBucket *)NIL) {
  1909.     bucketPtr->low |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1910.     } else {
  1911.     printf("VmMach_MakeNonCacheable: Not found\n");
  1912.     }
  1913.  
  1914.     MASTER_UNLOCK(vmMachMutexPtr);
  1915. }
  1916.  
  1917. static char *userMapAllocPtr = (char *) VMMACH_USER_MAPPING_BASE_ADDR;
  1918.  
  1919.  
  1920. /*
  1921.  *----------------------------------------------------------------------
  1922.  *
  1923.  * VmMach_UserMap --
  1924.  *
  1925.  *    Map the given range of kernel physical addresses into the
  1926.  *    given user's virtual address space.  This is only used for the X
  1927.  *    server and thus    there can only be one user mapping at once.
  1928.  *
  1929.  * Results:
  1930.  *    None.
  1931.  *
  1932.  * Side effects:
  1933.  *    None.
  1934.  *
  1935.  *----------------------------------------------------------------------
  1936.  */
  1937. ReturnStatus
  1938. VmMach_UserMap(numBytes, addr, physAddr,cache, newAddrPtr)
  1939.     int        numBytes;
  1940.     Address    addr;
  1941.     Address    physAddr;
  1942.     Boolean    cache;        /* Should the region be cacheable?. */
  1943.     Address    *newAddrPtr;
  1944. {
  1945.     int                i;
  1946.     Address            retAddr;
  1947.     unsigned            firstPhysPage;
  1948.     unsigned            lastPhysPage;
  1949.     VmMach_KernSharedInfo    *infoPtr;
  1950.     Proc_ControlBlock           *procPtr;
  1951.     ReturnStatus        status = SUCCESS;
  1952.     Vm_Segment              *segPtr;
  1953.     Vm_VirtAddr            virtAddr;
  1954.     Vm_PTE            *ptePtr;
  1955.     unsigned            physPage;
  1956.     Boolean            doAlloc;
  1957.  
  1958.     procPtr = Proc_GetCurrentProc();
  1959.     if (addr == (Address) NIL) {
  1960.     /* 
  1961.      * If we have to allocate the space ourselves then we allocate it
  1962.      * up above the stack in the user mapping region.  We add it to
  1963.      * the stack segment.  Note that the allocation algorithm is
  1964.      * really stupid. It assumes that only the X server is going to use
  1965.      * this allocation.
  1966.      */
  1967.     doAlloc = TRUE;
  1968.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  1969.     addr = (Address) ((unsigned) userMapAllocPtr | 
  1970.             ((unsigned) physAddr & VMMACH_OFFSET_MASK));
  1971.     if ((unsigned) userMapAllocPtr > (unsigned)
  1972.         (VMMACH_USER_MAPPING_BASE_ADDR + 
  1973.         VMMACH_USER_MAPPING_PAGES * vm_PageSize)) {
  1974.         printf("Out of mapping pages.\n");
  1975.         return FAILURE;
  1976.     }
  1977.     } else {
  1978.     doAlloc = FALSE;
  1979.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  1980.     }
  1981.     infoPtr = (VmMach_KernSharedInfo *) malloc(sizeof(VmMach_KernSharedInfo));
  1982.     bzero((char *) infoPtr, sizeof(*infoPtr));
  1983.     List_InitElement((List_Links *) infoPtr);
  1984.     firstPhysPage = (unsigned)physAddr >> VMMACH_PAGE_SHIFT;
  1985.     lastPhysPage = (unsigned)(physAddr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  1986.     infoPtr->firstPage = (unsigned) addr >> VMMACH_PAGE_SHIFT;
  1987.     infoPtr->lastPage = 
  1988.     (unsigned)(addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  1989.     if (!cache) {
  1990.     infoPtr->flags |= VMMACH_KERN_SHARED_UNCACHEABLE;
  1991.     }
  1992.     if (!doAlloc) {
  1993.     status = Vm_DeleteFromSeg(segPtr, infoPtr->firstPage, 
  1994.             infoPtr->lastPage);
  1995.     if (status != SUCCESS) {
  1996.         printf("VmMach_UserMap: Vm_DeleteFromSeg failed 0x%x\n", status);
  1997.         free((char *) infoPtr);
  1998.         return status;
  1999.     }
  2000.     status = VmAddToSeg(segPtr, infoPtr->firstPage, infoPtr->lastPage);
  2001.     if (status != SUCCESS) {
  2002.         printf("VmMach_UserMap: VmAddToSeg failed 0x%x\n", status);
  2003.         free((char *) infoPtr);
  2004.         return status;
  2005.     }
  2006.     virtAddr.segPtr = segPtr;
  2007.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  2008.     for(virtAddr.page = infoPtr->firstPage, 
  2009.         physPage = firstPhysPage,
  2010.         ptePtr = VmGetPTEPtr(segPtr, infoPtr->firstPage);
  2011.         virtAddr.page <= infoPtr->lastPage;
  2012.         virtAddr.page++, physPage++, VmIncPTEPtr(ptePtr, 1)) {
  2013.     
  2014.         *ptePtr |= VM_PHYS_RES_BIT | VM_REFERENCED_BIT;
  2015.         *ptePtr |= (physPage & VM_PAGE_FRAME_FIELD);
  2016.     }
  2017.     infoPtr->firstPhysPage = (unsigned) NIL;
  2018.     } else {
  2019.     userMapAllocPtr += (infoPtr->lastPage - infoPtr->firstPage + 1) * 
  2020.                 vm_PageSize;
  2021.     infoPtr->firstPhysPage = firstPhysPage;
  2022.     }
  2023.     List_Insert((List_Links *) infoPtr, 
  2024.     LIST_ATFRONT(&procPtr->vmPtr->machPtr->kernSharedList));
  2025.     /*
  2026.      * Make sure this process never migrates.
  2027.      */
  2028.     Proc_NeverMigrate(procPtr);
  2029.     *newAddrPtr = addr;
  2030.     return status;
  2031. }
  2032.  
  2033.  
  2034. /*
  2035.  *----------------------------------------------------------------------
  2036.  *
  2037.  * VmMach_UserUnmap --
  2038.  *
  2039.  *    Unmap all pages mapped into a user's address space.
  2040.  *
  2041.  * Results:
  2042.  *    None.
  2043.  *
  2044.  * Side effects:
  2045.  *    None.
  2046.  *
  2047.  *----------------------------------------------------------------------
  2048.  */
  2049. ENTRY ReturnStatus
  2050. VmMach_UserUnmap(addr)
  2051.     Address        addr;
  2052. {
  2053.     int                pid;
  2054.     Proc_ControlBlock        *procPtr;
  2055.     List_Links            *listPtr;
  2056.     VmMach_KernSharedInfo    *infoPtr;
  2057.     List_Links            *tmpPtr;
  2058.     int                page;
  2059.     Boolean            doAll = FALSE;
  2060.     ReturnStatus        status = SUCCESS;
  2061.     Vm_Segment              *segPtr;
  2062.     Vm_PTE            *ptePtr;
  2063.  
  2064.     procPtr = Proc_GetCurrentProc();
  2065.     pid = procPtr->vmPtr->machPtr->pid;
  2066.     if (addr == (Address) NIL) {
  2067.     doAll = TRUE;
  2068.     }
  2069.     page = (unsigned) addr >> VMMACH_PAGE_SHIFT;
  2070.     tmpPtr = (List_Links *) NIL;
  2071.     listPtr = &procPtr->vmPtr->machPtr->kernSharedList;
  2072.     LIST_FORALL(listPtr, (List_Links *) infoPtr) {
  2073.     if (doAll) {
  2074.         if (tmpPtr != (List_Links *) NIL) {
  2075.         List_Remove(tmpPtr);
  2076.         free((char *) tmpPtr);
  2077.         }
  2078.     }
  2079.     if (doAll || infoPtr->firstPage == page) {
  2080.         if (infoPtr->firstPage < VMMACH_USER_MAPPING_BASE_PAGE) {
  2081.         segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  2082.         for(ptePtr = VmGetPTEPtr(segPtr, infoPtr->firstPage);
  2083.             page <= infoPtr->lastPage;
  2084.             page++, VmIncPTEPtr(ptePtr, 1)) {
  2085.  
  2086.             *ptePtr = 0;
  2087.         }
  2088.         } else {
  2089.         userMapAllocPtr = (char *) VMMACH_USER_MAPPING_BASE_ADDR;
  2090.         }
  2091.         tmpPtr = (List_Links *) infoPtr;
  2092.         if (!doAll) {
  2093.         break;
  2094.         }
  2095.     }
  2096.     }
  2097.     if (tmpPtr != (List_Links *) NIL) {
  2098.     List_Remove(tmpPtr);
  2099.     free((char *) tmpPtr);
  2100.     } else if (!doAll) {
  2101.     return FAILURE;
  2102.     }
  2103.     if (pid != VMMACH_INV_PID && pid != VMMACH_KERN_PID) {
  2104.     MASTER_LOCK(vmMachMutexPtr);
  2105.     TLBHashFlushPID(pid);
  2106.     MASTER_UNLOCK(vmMachMutexPtr);
  2107.     }
  2108.     return SUCCESS;
  2109. }
  2110.  
  2111.  
  2112. #define ALLOC(x,s)    (sharedData->allocVector[(x)]=s)
  2113. #define FREE(x)        (sharedData->allocVector[(x)]=0)
  2114. #define SIZE(x)        (sharedData->allocVector[(x)])
  2115. #define ISFREE(x)    (sharedData->allocVector[(x)]==0)
  2116.  
  2117.  
  2118.  
  2119. /*
  2120.  * ----------------------------------------------------------------------------
  2121.  *
  2122.  * VmMach_Alloc --
  2123.  *
  2124.  *      Allocates a region of shared memory;
  2125.  *
  2126.  * Results:
  2127.  *      SUCCESS if the region can be allocated.
  2128.  *    The starting address is returned in addr.
  2129.  *
  2130.  * Side effects:
  2131.  *      The allocation vector is updated.
  2132.  *
  2133.  * ----------------------------------------------------------------------------
  2134.  */
  2135. static ReturnStatus
  2136. VmMach_Alloc(sharedData, regionSize, addr)
  2137.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  2138.     int            regionSize;    /* Size of region to allocate. */
  2139.     Address        *addr;        /* Address of region. */
  2140. {
  2141.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  2142.         VMMACH_SHARED_BLOCK_SIZE;
  2143.     int i, blockCount, firstBlock;
  2144.  
  2145.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  2146.         (int *)NIL) {
  2147.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  2148.     }
  2149.  
  2150.     /*
  2151.      * Loop through the alloc vector until we find numBlocks free blocks
  2152.      * consecutively.
  2153.      */
  2154.     blockCount = 0;
  2155.     for (i=sharedData->allocFirstFree;
  2156.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  2157.     if (ISFREE(i)) {
  2158.         blockCount++;
  2159.     } else {
  2160.         blockCount = 0;
  2161.         if (i==sharedData->allocFirstFree) {
  2162.         sharedData->allocFirstFree++;
  2163.         }
  2164.     }
  2165.     }
  2166.     if (blockCount < numBlocks) {
  2167.     dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  2168.         blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  2169.     return VM_NO_SEGMENTS;
  2170.     }
  2171.     firstBlock = i-blockCount;
  2172.     if (firstBlock == sharedData->allocFirstFree) {
  2173.     sharedData->allocFirstFree += blockCount;
  2174.     }
  2175.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  2176.         VMMACH_SHARED_START_ADDR);
  2177.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  2178.     ALLOC(i,numBlocks);
  2179.     }
  2180.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  2181.         numBlocks,firstBlock,*addr);
  2182.     return SUCCESS;
  2183. }
  2184.  
  2185.  
  2186. /*
  2187.  * ----------------------------------------------------------------------------
  2188.  *
  2189.  * VmMach_Unalloc --
  2190.  *
  2191.  *      Frees a region of shared address space.
  2192.  *
  2193.  * Results:
  2194.  *      None.
  2195.  *
  2196.  * Side effects:
  2197.  *      The allocation vector is updated.
  2198.  *
  2199.  * ----------------------------------------------------------------------------
  2200.  */
  2201.  
  2202. static void
  2203. VmMach_Unalloc(sharedData, addr)
  2204.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  2205.     Address    addr;        /* Address of region. */
  2206. {
  2207.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  2208.         VMMACH_SHARED_BLOCK_SIZE;
  2209.     int numBlocks = SIZE(firstBlock);
  2210.     int i;
  2211.  
  2212.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  2213.     if (firstBlock < sharedData->allocFirstFree) {
  2214.     sharedData->allocFirstFree = firstBlock;
  2215.     }
  2216.     for (i=0;i<numBlocks;i++) {
  2217.     if (ISFREE(i+firstBlock)) {
  2218.         printf("Freeing free shared address %d %d %d\n",i,i+firstBlock,
  2219.             (int)addr);
  2220.         return;
  2221.     }
  2222.     FREE(i+firstBlock);
  2223.     }
  2224. }
  2225.  
  2226. /*
  2227.  * ----------------------------------------------------------------------------
  2228.  *
  2229.  * VmMach_SharedStartAddr --
  2230.  *
  2231.  *      Determine the starting address for a shared segment.
  2232.  *
  2233.  * Results:
  2234.  *      Returns the proper start address for the segment.
  2235.  *
  2236.  * Side effects:
  2237.  *      Allocates part of the shared address space.
  2238.  *
  2239.  * ----------------------------------------------------------------------------
  2240.  */
  2241. ReturnStatus
  2242. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  2243.     Proc_ControlBlock   *procPtr;
  2244.     int             size;           /* Length of shared segment. */
  2245.     Address         *reqAddr;        /* Requested start address. */
  2246.     int             fixed;          /* 1 if fixed address requested. */
  2247. {
  2248.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  2249.             VMMACH_SHARED_BLOCK_SIZE;
  2250.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR+
  2251.             VMMACH_SHARED_BLOCK_SIZE-1) /
  2252.             VMMACH_SHARED_BLOCK_SIZE;
  2253.     int i;
  2254.     VmMach_SharedData   *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  2255.  
  2256.     if (fixed==0) {
  2257.         return VmMach_Alloc(sharedData, size, reqAddr);
  2258.     } else {
  2259.         for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  2260.             if (i>0) {
  2261.                 ALLOC(i,numBlocks);
  2262.             }
  2263.         }
  2264.         return SUCCESS;
  2265.     }
  2266. }
  2267.  
  2268. /*
  2269.  * ----------------------------------------------------------------------------
  2270.  *
  2271.  * VmMach_SharedProcStart --
  2272.  *
  2273.  *      Perform machine dependent initialization of shared memory
  2274.  *    for this process.
  2275.  *
  2276.  * Results:
  2277.  *      None.
  2278.  *
  2279.  * Side effects:
  2280.  *      The storage allocation structures are initialized.
  2281.  *
  2282.  * ----------------------------------------------------------------------------
  2283.  */
  2284. void
  2285. VmMach_SharedProcStart(procPtr)
  2286.     Proc_ControlBlock    *procPtr;
  2287. {
  2288.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  2289.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  2290.     if (sharedData->allocVector != (int *)NIL) {
  2291.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  2292.     }
  2293.     sharedData->allocVector =
  2294.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  2295.     sharedData->allocFirstFree = 0;
  2296.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  2297.         sizeof(int));
  2298.     procPtr->vmPtr->sharedStart = (Address) VMMACH_SHARED_START_ADDR;
  2299.     procPtr->vmPtr->sharedEnd = (Address) VMMACH_SHARED_START_ADDR+
  2300.         VMMACH_USER_SHARED_PAGES*VMMACH_PAGE_SIZE;
  2301. }
  2302.  
  2303. /*
  2304.  * ----------------------------------------------------------------------------
  2305.  *
  2306.  * VmMach_SharedSegFinish --
  2307.  *
  2308.  *      Perform machine dependent cleanup of shared memory
  2309.  *    for this segment.
  2310.  *
  2311.  * Results:
  2312.  *      None.
  2313.  *
  2314.  * Side effects:
  2315.  *      The storage allocation structures are freed.
  2316.  *
  2317.  * ----------------------------------------------------------------------------
  2318.  */
  2319. void
  2320. VmMach_SharedSegFinish(procPtr,addr)
  2321.     Proc_ControlBlock    *procPtr;
  2322.     Address        addr;
  2323. {
  2324.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  2325. }
  2326.  
  2327. /*
  2328.  * ----------------------------------------------------------------------------
  2329.  *
  2330.  * VmMach_SharedProcFinish --
  2331.  *
  2332.  *      Perform machine dependent cleanup of shared memory
  2333.  *    for this process.
  2334.  *
  2335.  * Results:
  2336.  *      None.
  2337.  *
  2338.  * Side effects:
  2339.  *      The storage allocation structures are freed.
  2340.  *
  2341.  * ----------------------------------------------------------------------------
  2342.  */
  2343. void
  2344. VmMach_SharedProcFinish(procPtr)
  2345.     Proc_ControlBlock    *procPtr;
  2346. {
  2347.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  2348.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  2349.     procPtr->vmPtr->machPtr->sharedData.allocVector;
  2350.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  2351. }
  2352.  
  2353. /*
  2354.  * ----------------------------------------------------------------------------
  2355.  *
  2356.  * VmMach_CopySharedMem --
  2357.  *
  2358.  *      Copies machine-dependent shared memory data structures to handle
  2359.  *    a fork.
  2360.  *
  2361.  * Results:
  2362.  *      None.
  2363.  *
  2364.  * Side effects:
  2365.  *      The new process gets a copy of the shared memory structures.
  2366.  *
  2367.  * ----------------------------------------------------------------------------
  2368.  */
  2369. void
  2370. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  2371.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  2372.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  2373. {
  2374.     VmMach_SharedData    *childSharedData =
  2375.         &childProcPtr->vmPtr->machPtr->sharedData;
  2376.     VmMach_SharedData    *parentSharedData =
  2377.         &parentProcPtr->vmPtr->machPtr->sharedData;
  2378.  
  2379.     VmMach_SharedProcStart(childProcPtr);
  2380.  
  2381.     bcopy(parentSharedData->allocVector, childSharedData->allocVector,
  2382.         VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  2383.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  2384. }
  2385.  
  2386. /*
  2387.  * ----------------------------------------------------------------------------
  2388.  *
  2389.  * VmMach_LockCachePage --
  2390.  *
  2391.  *      Perform machine dependent locking of a kernel resident file cache
  2392.  *    page.
  2393.  *
  2394.  * Results:
  2395.  *      None.
  2396.  *
  2397.  * Side effects:
  2398.  *
  2399.  * ----------------------------------------------------------------------------
  2400.  */
  2401. void
  2402. VmMach_LockCachePage(kernelAddress)
  2403.     Address    kernelAddress;    /* Address on page to lock. */
  2404. {
  2405.     /*
  2406.      * Ds3100 leaves file cache pages always available so there is no need to
  2407.      * lock or unlock them.
  2408.      */
  2409.     return;
  2410. }
  2411.  
  2412. /*
  2413.  * ----------------------------------------------------------------------------
  2414.  *
  2415.  * VmMach_UnlockCachePage --
  2416.  *
  2417.  *      Perform machine dependent unlocking of a kernel resident page.
  2418.  *
  2419.  * Results:
  2420.  *      None.
  2421.  *
  2422.  * Side effects:
  2423.  *
  2424.  * ----------------------------------------------------------------------------
  2425.  */
  2426. void
  2427. VmMach_UnlockCachePage(kernelAddress)
  2428.     Address    kernelAddress;    /* Address on page to unlock. */
  2429. {
  2430.     /*
  2431.      * Ds3100 leaves file cache pages always available so there is no need to
  2432.      * lock or unlock them.
  2433.      */
  2434.     return;
  2435. }
  2436.  
  2437.